package cn.zebra.dev.admin.module.product.controller;

import cn.zebra.dev.admin.module.login.SecurityAdminService;
import cn.zebra.dev.admin.module.product.dto.*;
import cn.zebra.dev.admin.module.product.vo.ProductQueryVO;
import cn.zebra.dev.admin.module.product.vo.ProductSaleVO;
import cn.zebra.dev.admin.module.product.vo.ProductVO;
import cn.zebra.dev.common.restful.Result;
import cn.zebra.dev.common.utils.ObjectUtils;
import cn.zebra.dev.ibatis.plus.utils.PageUtils;
import cn.zebra.dev.product.module.category.entity.ProductCategoryEntity;
import cn.zebra.dev.product.module.category.service.ProductCategoryService;
import cn.zebra.dev.product.module.product.constant.ProductStatusConstant;
import cn.zebra.dev.product.module.product.entity.ProductEntity;
import cn.zebra.dev.product.module.product.service.ProductService;
import cn.zebra.dev.product.module.sku.entity.ProductSkuAttributeEntity;
import cn.zebra.dev.product.module.sku.entity.ProductSkuEntity;
import cn.zebra.dev.product.module.sku.service.ProductSkuAttributeService;
import cn.zebra.dev.product.module.sku.service.ProductSkuService;
import cn.zebra.dev.product.moudle.brand.entity.ProductBrandEntity;
import cn.zebra.dev.product.moudle.brand.service.ProductBrandService;
import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author runnable@sina.cn
 */
@Api(tags = "商品管理")
@RestController
@RequestMapping("/product")
public class ProductController {

    @Autowired
    private SecurityAdminService adminService;

    @Autowired
    private ProductService productService;

    @Autowired
    private ProductSkuService skuService;

    @Autowired
    private ProductSkuAttributeService productAttributeService;

    @Autowired
    private ProductCategoryService productCategoryService;

    @Autowired
    private ProductBrandService productBrandService;

    @GetMapping("/list")
    @ApiOperation("商品列表")
    public Result<PageUtils<ProductListDTO>> list(
            ProductQueryVO params,
            @RequestParam(value = "limit", defaultValue = "10", required = false) Integer limit,
            @RequestParam(value = "page", defaultValue = "1", required = false) Integer page) {
        Map<String, Object> map = ObjectUtils.objectConvertMap(params);
        map.put("productType", 0);
        map.put("limit", limit);
        map.put("page", page);
        PageUtils<ProductEntity> pageUtils = productService.findPage(map);
        PageUtils<ProductListDTO> data = new PageUtils<>(pageUtils);
        List<ProductEntity> list = pageUtils.getList();
        if (list.size() > 0) {
            List<ProductListDTO> dtoList = new LinkedList<>();
            Set<Long> productIds = list.stream().map(ProductEntity::getId).collect(Collectors.toSet());
            List<ProductSkuEntity> skuEntities = skuService.findListByProductIds(productIds);
            list.forEach(entity -> {
                Long productId = entity.getId();
                List<ProductSkuEntity> skuList = skuEntities.stream().filter(sku -> sku.getProductId().equals(productId)).collect(Collectors.toList());
                ProductListDTO dto = new ProductListDTO();
                BeanUtils.copyProperties(entity, dto);
                if (skuList.size() > 0) {
                    dto.setMinPrice(skuList.stream().map(ProductSkuEntity::getUnitPrice).min(BigDecimal::compareTo).get());
                    dto.setMaxPrice(skuList.stream().map(ProductSkuEntity::getUnitPrice).max(BigDecimal::compareTo).get());
                }
                dtoList.add(dto);
            });
            data.setList(dtoList);
        }
        return Result.success(data);
    }

    @GetMapping("/exportExcel")
    @ApiOperation("导出商品到Excel表格")
    public void exportExcel(HttpServletResponse response) throws IOException {
        List<ProductEntity> list = productService.findList();
        ServletOutputStream outputStream = response.getOutputStream();
        response.setContentType("application/octet-stream");
        response.setHeader("Content-Disposition", "attachment; filename=" + System.currentTimeMillis() + ".xlsx");
        List<ProductExcelDTO> dtoList = new LinkedList<>();
        list.forEach(entity -> {
            ProductExcelDTO dto = new ProductExcelDTO();
            BeanUtils.copyProperties(entity, dto);
            dtoList.add(dto);
        });
        EasyExcel.write(outputStream, ProductExcelDTO.class).sheet("sheet1").doWrite(dtoList);
        outputStream.close();
    }

    @GetMapping("/get/{id}")
    @ApiOperation("查看商品信息")
    public Result<ProductDTO> get(@PathVariable Long id) {
        ProductEntity product = productService.findById(id);
        List<ProductSkuAttributeEntity> attrs = productAttributeService.findListByProductId(id);
        Set<Long> skuIds = attrs.stream().map(ProductSkuAttributeEntity::getProductSkuId).collect(Collectors.toSet());
        List<ProductSkuEntity> skuEntityList = skuService.findByIds(skuIds);
        ProductDTO dto = new ProductDTO();
        BeanUtils.copyProperties(product, dto);
        List<ProductSkuDTO> skuList = new LinkedList<>();
        skuEntityList.forEach(skuEntity -> {
            ProductSkuDTO skuDto = new ProductSkuDTO();
            BeanUtils.copyProperties(skuEntity, skuDto);
            List<ProductSkuAttributeDTO> attributeDTOList = new LinkedList<>();
            List<ProductSkuAttributeEntity> attrEntities = attrs.stream().filter(entity -> entity.getProductSkuId().equals(skuEntity.getId())).collect(Collectors.toList());
            attrEntities.forEach(attrEntity -> {
                ProductSkuAttributeDTO attributeDTO = new ProductSkuAttributeDTO();
                BeanUtils.copyProperties(attrEntity, attributeDTO);
                attributeDTOList.add(attributeDTO);
            });
            skuDto.setAttrEntities(attributeDTOList);
            skuList.add(skuDto);
        });
        dto.setSkuList(skuList);
        return Result.success(dto);
    }

    @PostMapping("/sale")
    @ApiOperation("商品上下架设置(批量)")
    public Result sale(@Valid @RequestBody ProductSaleVO params) {
        ProductEntity entity = new ProductEntity();
        entity.setSaleFlag(params.getSale());
        UpdateWrapper<ProductEntity> wrapper = new UpdateWrapper<>();
        wrapper.in("id", params.getProductId());
        if (productService.update(entity, wrapper)) {
            return Result.success("设置成功!");
        }
        return Result.error("设置失败!");
    }

    @GetMapping("/delete/{id}")
    @ApiOperation("删除商品信息")
    public Result delete(@PathVariable Long id) {
        ProductEntity entity = new ProductEntity();
        entity.setDeleteFlag(true);
        if (productService.update(entity, "id = {0}", id)) {
            return Result.success("删除成功");
        }
        return Result.error("删除失败!");
    }

    @PostMapping("/save")
    @ApiOperation("新增商品信息")
    @Transactional(rollbackFor = Exception.class)
    public Result save(@Valid @RequestBody ProductVO vo) {
        Long createId = adminService.getId();
        ProductEntity productEntity = new ProductEntity();
        BeanUtils.copyProperties(vo, productEntity);
        productEntity.setStatus(ProductStatusConstant.WAIT);
        productEntity.setStatusRemark("");
        //保存商品
        if (!productService.saveProduct(productEntity, createId)) {
            return Result.error("保存商品失败!");
        }
        //保存商品SKU
        Long productId = productEntity.getId();
        List<ProductSkuEntity> skuEntities = getSkuList(vo);
        if (!skuService.save(productId, skuEntities, createId)) {
            throw new RuntimeException("保存sku信息失败");
        }
        //保存商品分类
        saveCategory(vo, productId);
        //保存商品品牌信息
        saveBrand(vo,productId);
        return Result.success("新增商品成功");
    }

    private void saveCategory(ProductVO vo, Long productId) {
        List<Long> categoryIds = vo.getCategoryIds();
        if (categoryIds != null && categoryIds.size() > 0) {
            List<ProductCategoryEntity> list = new ArrayList<>();
            for (Long categoryId : categoryIds) {
                ProductCategoryEntity categoryEntity = new ProductCategoryEntity();
                categoryEntity.setCategoryId(categoryId);
                categoryEntity.setProductId(productId);
                list.add(categoryEntity);
            }
            if (!productCategoryService.saveBatch(list)) {
                throw new RuntimeException("保存商品分类信息失败!");
            }
        }
    }

    private void saveBrand(ProductVO vo, Long productId){
        ProductBrandEntity productBrandEntity = new ProductBrandEntity();
        productBrandEntity.setId(null);
        productBrandEntity.setBrandId(vo.getProductBrandId());
        productBrandEntity.setProductId(productId);
        if (!productBrandService.save(productBrandEntity)){
            throw new RuntimeException("保存商品品牌信息失败！");
        }
    }

    @PostMapping("/update/{id}")
    @ApiOperation("修改商品信息")
    @Transactional(rollbackFor = Exception.class)
    public Result update(@PathVariable Long id, @Valid @RequestBody ProductVO vo) {
        Long updateId = adminService.getId();
        ProductEntity productEntity = new ProductEntity();
        BeanUtils.copyProperties(vo, productEntity);
        //修改商品信息
        if (!productService.updateProduct(id, productEntity, updateId)) {
            return Result.error("保存商品失败!");
        }
        List<ProductSkuEntity> skuEntities = getSkuList(vo);
        //修改商品SKU信息
        if (!skuService.update(id, skuEntities, updateId)) {
            throw new RuntimeException("保存sku信息失败");
        }
        //修改商品分类绑定信息 先删除旧绑定 再新增
        productCategoryService.deleteByProductId(id);
        saveCategory(vo, id);
        return Result.success();
    }

    private List<ProductSkuEntity> getSkuList(ProductVO vo) {
        List<ProductSkuEntity> skuEntities = new LinkedList<>();
        vo.getSkuList().forEach(productSkuVO -> {
            ProductSkuEntity skuEntity = new ProductSkuEntity();
            BeanUtils.copyProperties(productSkuVO, skuEntity);
            List<ProductSkuAttributeEntity> attrEntities = new LinkedList<>();
            productSkuVO.getAttrEntities().forEach(attrVO -> {
                ProductSkuAttributeEntity attributeEntity = new ProductSkuAttributeEntity();
                BeanUtils.copyProperties(attrVO, attributeEntity);
                attrEntities.add(attributeEntity);
            });
            skuEntity.setAttrEntities(attrEntities);
            skuEntities.add(skuEntity);
        });
        return skuEntities;
    }
}